#include <osg/Geometry>
#include "RotationsKoerper.h"
#include "Funktionen.h"

#ifndef PI
#define PI    3.14159265358979323846f
#endif
#ifndef e
#define e    2.71828183
#endif

using namespace osg;
using namespace std;

Rotationskoerper::Rotationskoerper(const double height, bool boolean, double (Funktionen::*funktion)(double x, bool abb)){
	lsteps = 50;
	wsteps = 50;
	hoehe = height;
	flaechenKoerpern = boolean;
	funktionsZeiger = funktion;
	funtionsInstance = new Funktionen();

	aufbauen();
}

void Rotationskoerper::aufbauen(){

	rect = new Geometry;
	ref_ptr<Vec3Array> vertices = new Vec3Array();
	ref_ptr<Vec3Array> normals = new Vec3Array();
	ref_ptr<DrawElementsUInt> indices = new DrawElementsUInt(GL_TRIANGLE_STRIP);

	double xstep = 2*PI / lsteps;
	double ystep = hoehe / wsteps;
	/** current vertex coordinates **/
	double x = 0.0;
	double y = 0.0;

		ref_ptr<Vec2Array> texcoords = new Vec2Array;

	/** set vertices and normals **/
	for (int i=0; i<=wsteps; i++){
		x = 0.0;
		for (int j=0; j<= lsteps; j++){
			Vec3d normal;
			if(flaechenKoerpern == false){
				/** Fuer Kegel Zylinder Schachfiguren Saeulen **/
				vertices->push_back(Vec3d(((funtionsInstance->*funktionsZeiger)(y,true))*cos(x),(funtionsInstance->*funktionsZeiger)(y,true)*sin(x),y));
				normal.set((funtionsInstance->*funktionsZeiger)(y,false)*cos(x),(funtionsInstance->*funktionsZeiger)(y,false)*sin(x),1);
				texcoords->push_back(Vec2(x,y));
			}else{
				/** Fuer andere Flaechen z.B. Aschenbescher **/
				vertices->push_back(Vec3d(y*cos(x),y*sin(x),(funtionsInstance->*funktionsZeiger)(y,true)));
				normal.set(cos(x),sin(x),(funtionsInstance->*funktionsZeiger)(y,false));
				texcoords->push_back(Vec2(x,y));
			}
			normal.normalize();
			normals->push_back(normal);

			x +=xstep;
		}
		y +=ystep;
	}

	for (int i=0; i <lsteps; i+=2){
		for (int j=0; j<=wsteps; j++){
			indices->push_back( i*(wsteps+1)+j );
			indices->push_back( (i+1)*(wsteps+1)+j );
		}
		if ((i+2)*(wsteps+1)+wsteps < (lsteps+1)*(wsteps+1) ){
			for (int j=wsteps; j>=0; j--){
				indices->push_back( (i+2)*(wsteps+1)+j );
				indices->push_back( (i+1)*(wsteps+1)+j );
			}
		}
	}

	rect->setVertexArray (vertices.get());
	rect->addPrimitiveSet(indices.get());
	rect->setNormalArray(normals.get());
	rect->setNormalBinding(Geometry::BIND_PER_VERTEX);
	/** Textur setzen **/
	rect->setTexCoordArray(0,texcoords.get());
}

Geometry* Rotationskoerper::get(){
	return rect.release();
}

/** Freigeben der Resourcen **/
Rotationskoerper::~Rotationskoerper(){
	free(rect);
	free(funtionsInstance);
}
